//Note: this is the vector version of GGT, used with the corresponding grammar

package genome;

import java.util.ArrayList;

import tool.Utility;

import coevolution.GGTGenerator;

public class GGT extends Genotype {
	
	public static int[] fixedVector = {1,1};
	private int max;
	public int maxDepth;
	private double PMUTATE = 0.1;
	
	//maxDepth is equivalent to max nodes in the CGP version
	public GGT(double[] in, int sz, int mx, int maxDepth) {
		super(in, sz);
		this.input = in;
		this.size = sz;
		this.max = mx;
		this.maxDepth = maxDepth;
		
		for(int i=0;i<this.size;i++){
			this.genome[i]=GGTGenerator.R.nextInt(max);
		}
	}

	
	public double[] toVector(){
		double[] out  = new double[fixedVector.length];
		for(int i=0;i<fixedVector.length;i++){
			this.input[0] = fixedVector[i];
			this.input[1] = i;
			out[i] = this.eval();
		}
		return out;
	}
	
	public static void main(String[] args) {
		
		double[] in = {0.0,0.0};
		int size = 6;
		
		GGT g = new GGT(in,size,1,3);
		ArrayList<Genotype> space = g.generateSpace();
		for(Genotype g2:space){
			//System.out.println(g2);
			//System.out.println(g2.toMathString());
			double[] x = g2.toVector(); System.out.println(g2+" "+x[0]+" "+x[1]);
			//System.out.println("-----");
		}
	}

	public double eval() {
		grammar.setGGT(this);
		return grammar.eval();
	}
	
	public String toMathString(){
		grammar.setGGT(this);
		return grammar.evalS();
	}


	
	public GGT pointMutate(){
		//System.out.println("Point mutation");
		GGT gCopy = this.getCopy();
		gCopy.genome[GGTGenerator.R.nextInt(this.size)] = GGTGenerator.R.nextInt(max);
		return gCopy;
	}
	
	public GGT getCopy(){
		double[] i = new double[this.size];
		System.arraycopy(input, 0, i, 0, input.length);
		GGT g = new GGT(i, this.size,this.max,this.maxDepth);
		int[] gn = new int[this.size];
		System.arraycopy(this.genome,0,gn,0,genome.length);
		g.setGenome(gn);
		return g;
	}
	
	public Genotype stoMutate(){
		GGT gCopy = this.getCopy();
		for(int i=0;i<this.size;i++){
			if(GGTGenerator.R.nextDouble()<PMUTATE){
				gCopy.genome[i] = GGTGenerator.R.nextInt(max);
			}
		}
		
		return gCopy;
	}
	
	public void clear(int x){
		//zeros current genome up to x
		for (int i = 0; (i < x && i< genome.length); i++) {
			genome[i] = 0;
		}
	}
	
	public ArrayList<Genotype> generateSpace(){
		//returns whole GGT genotype space based on current parameters of this genome, using increment
		ArrayList<Genotype> space = new ArrayList<Genotype>();
		GGT g = this.getCopy();
		g.clear(g.size);
		space.add(g);
		int s = g.max+1;
		for(int i=0;i<Math.pow(s,g.size)-1;i++){
			g = g.increment();
			space.add(g);
		}
		return space;
	}
	
	public GGT increment(){
		//returns an incremented version of the current genome
		GGT g = this.getCopy();
		boolean incremented = false;
		int i=0;
		while(!incremented && i<g.genome.length){
			if(genome[i]+1<=max){
				g.genome[i] = g.genome[i]+1;
				g.clear(i);
				incremented = true;
			}
			else {
				i = i+1;
			}
		}
		return g;
	}
	

	@Override
	public String getConstantString() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setConstants(double[] d) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public double[] getSymbolicValues() {
		int num = 11;
		double[] vals = new double[num];
		
		//evaluate over range -1:+1
		double lBound = -1.0; double uBound = 1.0;
		double n = -1.0;
		double incr = (uBound-lBound)/(num-1);
		for(int i=0;i<num;i++){
			this.input[0] = n;
			vals[i] = this.eval();
			n = n+incr;
		}
		
		return vals;
	}


	@Override
	public double distanceTo(Genotype g) {
		// TODO Auto-generated method stub
		return 0;
	}


	@Override
	public ArrayList<Genotype> generateSpace(int samples) {
		ArrayList<Genotype> space = new ArrayList<Genotype>();
		for (int i = 0; i < samples; i++) {
			double[] inp = new double[this.input.length];
			System.arraycopy(this.input, 0, inp, 0, this.input.length);
			GGT g = new GGT(inp,this.size,this.max,this.maxDepth);
			space.add(g);
		}
		return space;
	}


	@Override
	public double quickSymbolicRegression(int samples, double[] range) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	

}
